#include "time_wrapper.h"
#include <stdexcept>
#include <iostream>

#ifdef MY_NAMESPACE_BEGIN
MY_NAMESPACE_BEGIN
#endif

TimeWrapper::TimeWrapper(){
	mSimpleTime= 0;
	memset( &mBrokenDown, 0, sizeof(mBrokenDown) );
	mbInited = false;
}

TimeWrapper::TimeWrapper( const time_t& sec ){
	mSimpleTime= 0;
	memset( &mBrokenDown, 0, sizeof(mBrokenDown) );
	SetTime( sec );
	mbInited = true;
}

TimeWrapper::TimeWrapper( const struct tm& brokenDown ){
	mSimpleTime= 0;
	memset( &mBrokenDown, 0, sizeof(mBrokenDown) );
	SetTime( brokenDown );
	mbInited = true;
}

TimeWrapper::TimeWrapper( const std::string& dateTimeString,
			const std::string& format ){
	mSimpleTime= 0;
	memset( &mBrokenDown, 0, sizeof(mBrokenDown) );
	SetTime( dateTimeString, format );
	mbInited = true;
}

void TimeWrapper::FillTmFromTimeT(	const time_t& sec,
					struct tm& brokendown ){
	struct tm tmp_tm, *ptm;
	ptm = localtime_r( &sec, &tmp_tm );
	if( NULL == ptm ){
		throw std::runtime_error("call localtime_r failed at TimeWrapper::FillTmFromTimeT");
	}else{
		brokendown = *ptm;
	}
	return;
}

void TimeWrapper::FillTimeTFromTm(	const struct tm& brokenDownConst, 
					time_t& sec,
					struct tm& brokenDown ){
	struct tm tmpBrokenDown = brokenDownConst;
//	time_t tmpTime1 = mktime( &tmpBrokenDown );
	time_t tmpTime = timegm( &tmpBrokenDown );
	if( -1 == tmpTime ){
		throw std::runtime_error("call timegm failed at TimeWrapper::FillTimeTFromTm");
	}else{
		sec = tmpTime-brokenDownConst.tm_gmtoff;
		FillTmFromTimeT( sec, brokenDown );
	}
	return;
}

void TimeWrapper::FillTimeTFromStr(const std::string& dateTimeString,
					const std::string& fmt,
					time_t& second,
					struct tm& brokenDown ){
	std::string format = fmt;
	if( format.empty() ){
		format = "%a, %d %b %Y %H:%M:%S %z"; 
	}
	struct tm tmpBrokenDown;
	memset( &tmpBrokenDown, 0, sizeof( tmpBrokenDown));
	if( NULL == strptime( dateTimeString.c_str(), format.c_str(), &tmpBrokenDown ) ){
		std::string errDesc = "call strptime failed at TimeWrapper::FillTimeTFromStr. ";
		errDesc += "Date and time string: ";
		errDesc += dateTimeString;
		throw std::runtime_error( errDesc );
	}else{
		FillTimeTFromTm( tmpBrokenDown, second, brokenDown );
	}
	return;
}

void TimeWrapper::ConvertTmToStr(	const struct tm& brokenDown,
					std::string& timeStr,
					const std::string& fmt ) const{
	char buf[257];
	memset( buf, 0, 257);
	std::string format = fmt;
	if( format.empty() ){
		format = "%a, %d %b %Y %H:%M:%S %z"; 
	}
	size_t ret = strftime( buf, 256, format.c_str(), &brokenDown );
	if( 0 != ret ){
		timeStr = buf;
	}
	return;
}

void TimeWrapper::SetTime( const time_t& sec ){
	mSimpleTime = sec;
	FillTmFromTimeT( sec, mBrokenDown );
	mbInited = true;
	return;
}

void TimeWrapper::SetTime( const struct tm& brokenDown ){	
	FillTimeTFromTm( brokenDown, mSimpleTime, mBrokenDown );
	mbInited = true;
	return;
}

void TimeWrapper::SetTime(	const std::string& dateTimeString,
				const std::string& format ){
	FillTimeTFromStr( dateTimeString, format, mSimpleTime, mBrokenDown );
	mbInited = true;
	return; 
}

time_t TimeWrapper::GetTimeSec() const{
	return mSimpleTime;
}

const struct tm& TimeWrapper::GetTimeTm() const{
	return mBrokenDown;
}

std::string TimeWrapper::GetTimeStr( const std::string& format ) const{
	std::string timeStr;
	ConvertTmToStr( mBrokenDown, timeStr, format );
	return timeStr;
}

bool TimeWrapper::IsInited() const{
	return mbInited;
}

void TimeWrapper::PrintTm( const std::string& prefix ) const{
	std::string prefixStr;
	if( prefix.size() ){
		prefixStr = prefix;
		prefixStr += " ";
	}
	std::cout << prefixStr << "Broken down:" << std::endl;
	std::cout << "    " << "Year:" << mBrokenDown.tm_year+1900 <<std::endl;
	std::cout << "    " << "Mon :" << mBrokenDown.tm_mon+1	<<std::endl;
	std::cout << "    " << "Day :" << mBrokenDown.tm_mday	<<std::endl;
	std::cout << "    " << "Hour:" << mBrokenDown.tm_hour	<<std::endl;
	std::cout << "    " << "Min :" << mBrokenDown.tm_min	<<std::endl;
	std::cout << "    " << "Sec :" << mBrokenDown.tm_sec	<<std::endl;
	std::cout << "    " << "WDay:" << mBrokenDown.tm_wday	<<std::endl;
	std::cout << "    " << "GOff:" << mBrokenDown.tm_gmtoff	<<std::endl;
	std::cout << "    " << "Dst :" << mBrokenDown.tm_isdst	<<std::endl;
	return;
}

#ifdef MY_NAMESPACE_END
MY_NAMESPACE_END
#endif
